package main

import (
	"io"
	"io/ioutil"
	"path/filepath"
	"regexp"
	"strconv"

	"github.com/dchest/jsmin"
)

var (
	serno      = 0
	components = map[string]int{}
)

var (
	regexpTemplate      = regexp.MustCompile(`<template>[^\0]*</template>`)
	regexpTemplateTag   = regexp.MustCompile(`</?template>`)
	regexpTemplateLine  = regexp.MustCompile(`[\r\n]+`)
	regexpTemplateBlank = regexp.MustCompile(`>\s+<`)
	regexpTemplateQuote = regexp.MustCompile(`'`)
	regexpScript        = regexp.MustCompile(`<script>[^\0]*</script>`)
	regexpScriptTag     = regexp.MustCompile(`</?script>`)
	regexpImport        = regexp.MustCompile(`import[^;\n]+[;\n]`)
	regexpImportImport  = regexp.MustCompile(`import`)
	regexpImportFrom    = regexp.MustCompile(`from`)
	regexpImportEnd     = regexp.MustCompile(`[;\n]`)
	regexpImportPath    = regexp.MustCompile(`'.*'`)
	regexpExport        = regexp.MustCompile(`export default`)
)

// 转化vue文件，返回该组件的索引
func cvue(w io.Writer, path string) int {
	if i, ok := components[path]; ok {
		return i
	}
	index := serno
	serno += 1
	components[path] = index

	src, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}
	tmpl, script := split(src)
	if len(script) > 0 {
		// export
		script = regexpExport.ReplaceAll(script, []byte(`_cvue[`+strconv.Itoa(index)+`]=`))
		// import
		script = cimport(w, path, script)
	} else {
		script = []byte(`_cvue[` + strconv.Itoa(index) + `]={};`)
	}

	script, err = jsmin.Minify(script)
	if err != nil {
		panic(err)
	}
	w.Write(script)
	w.Write([]byte("\n_cvue[" + strconv.Itoa(index) + "].template=" + string(tmpl) + ";"))
	return index
}

// 将数据分成template、script两部份
func split(src []byte) ([]byte, []byte) {
	t := regexpTemplateTag.ReplaceAll(regexpTemplateQuote.ReplaceAll(regexpTemplateBlank.ReplaceAll(regexpTemplateLine.ReplaceAll(regexpTemplate.Find(src), []byte(` `)), []byte(`><`)), []byte(`\'`)), []byte(`'`))
	s := regexpScriptTag.ReplaceAll(regexpScript.Find(src), []byte(``))
	return t, s
}

// 执行import转换
func cimport(w io.Writer, path string, script []byte) []byte {
	return regexpImport.ReplaceAllFunc(script, func(s []byte) []byte {
		s = regexpImportImport.ReplaceAll(s, []byte(`var`))
		s = regexpImportFrom.ReplaceAll(s, []byte(`=Vue.extend(_cvue[`))
		s = regexpImportEnd.ReplaceAll(s, []byte(`]);`))
		s = regexpImportPath.ReplaceAllFunc(s, func(p []byte) []byte {
			i := cvue(w, filepath.Join(filepath.Dir(path), string(p[1:len(p)-1])))
			return []byte(strconv.Itoa(i))
		})
		return s
	})
}
